package org.firefly.service;

import org.firefly.entity.TimeCapsule;
import org.firefly.repository.TimeCapsuleRepository;
import org.firefly.util.GeoUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class LocationTriggerService {

    private static final Logger log = LoggerFactory.getLogger(LocationTriggerService.class);
    private static final double DEFAULT_TRIGGER_DISTANCE = 100; // 100米

    private final TimeCapsuleRepository capsuleRepository;
    private final TimeCapsuleService capsuleService;
    private final ScheduledExecutorService locationMonitorExecutor;

    // 位置胶囊缓存 (capsuleId -> CapsuleData)
    private final Map<Long, CapsuleData> monitoredCapsules = new ConcurrentHashMap<>();

    // 用户位置缓存 (userId -> UserLocation)
    private final Map<Long, UserLocation> userLocations = new ConcurrentHashMap<>();

    // 位置更新策略
    @Value("${location.update-strategy:INTELLIGENT}")
    private UpdateStrategy updateStrategy;

    // 最大监控胶囊数
    @Value("${location.max-monitored:1000}")
    private int maxMonitoredCapsules;

    // 位置更新频率（毫秒）
    @Value("${location.update-interval:300000}")
    private long updateInterval;

    // 后台同步间隔（分钟）
    @Value("${location.sync-interval:10}")
    private int syncIntervalMinutes;

    // 智能更新阈值（米）
    @Value("${location.intelligent-threshold:5000}")
    private double intelligentThreshold;

    // 最后同步时间
    private Instant lastSyncTime = Instant.MIN;

    @Autowired
    public LocationTriggerService(TimeCapsuleRepository capsuleRepository,
                                  TimeCapsuleService capsuleService) {
        this.capsuleRepository = capsuleRepository;
        this.capsuleService = capsuleService;
        this.locationMonitorExecutor = Executors.newSingleThreadScheduledExecutor();
    }

    @PostConstruct
    public void init() {
        log.info("Starting location monitoring service...");
        reloadMonitoredCapsules();
        startLocationMonitoring();
    }

    @PreDestroy
    public void shutdown() {
        log.info("Shutting down location monitoring service...");
        locationMonitorExecutor.shutdownNow();
        monitoredCapsules.clear();
        userLocations.clear();
    }

    /**
     * 添加位置胶囊到监控
     */
    public void addToMonitoring(TimeCapsule capsule) {
        if (!isValidLocationCapsule(capsule)) {
            log.warn("Invalid location capsule, not added to monitoring: {}", capsule.getId());
            return;
        }

        if (monitoredCapsules.size() >= maxMonitoredCapsules) {
            log.warn("Location monitoring capacity reached, unable to add new capsule: {}", capsule.getId());
            return;
        }

        CapsuleData data = new CapsuleData(
                capsule.getId(),
                capsule.getLatitude(),
                capsule.getLongitude(),
                capsule.getUser().getId(),
                DEFAULT_TRIGGER_DISTANCE
        );

        monitoredCapsules.put(capsule.getId(), data);
        log.info("Added location capsule to monitoring: ID={}, Lat={}, Lng={}",
                capsule.getId(), capsule.getLatitude(), capsule.getLongitude());
    }

    /**
     * 从监控中移除位置胶囊
     */
    public void removeFromMonitoring(Long capsuleId) {
        CapsuleData removed = monitoredCapsules.remove(capsuleId);
        if (removed != null) {
            log.info("Removed location capsule from monitoring: ID={}", capsuleId);
        }
    }

    /**
     * 更新用户位置
     *
     * @param userId 用户ID
     * @param latitude 纬度
     * @param longitude 经度
     * @param accuracy 定位精度（米）
     */
    public void updateUserLocation(Long userId, double latitude, double longitude, double accuracy) {
        UserLocation location = userLocations.computeIfAbsent(userId,
                id -> new UserLocation(id, latitude, longitude, accuracy));

        location.setLatitude(latitude);
        location.setLongitude(longitude);
        location.setAccuracy(accuracy);
        location.setLastUpdate(Instant.now()); // 设置最后更新时间

        // 智能触发检查
        if (updateStrategy == UpdateStrategy.INTELLIGENT) {
            checkIntelligentTrigger(userId);
        }
    }

    /**
     * 后台定时任务：重新加载位置胶囊
     */
    @Scheduled(fixedRateString = "${location.sync-interval-minutes:10}", timeUnit = TimeUnit.MINUTES)
    public void reloadMonitoredCapsules() {
        log.info("Reloading monitored location capsules...");

        // 修复：使用新添加的仓库方法
        List<TimeCapsule> locationCapsules = capsuleRepository
                .findByTypeAndOpenedFalse(TimeCapsule.CapsuleType.LOCATION);

        // 更新缓存
        Set<Long> currentIds = new HashSet<>(monitoredCapsules.keySet());
        Set<Long> newIds = new HashSet<>();

        for (TimeCapsule capsule : locationCapsules) {
            newIds.add(capsule.getId());
            if (!monitoredCapsules.containsKey(capsule.getId())) {
                addToMonitoring(capsule);
            }
        }

        // 移除已不存在的胶囊
        currentIds.removeAll(newIds);
        currentIds.forEach(this::removeFromMonitoring);

        lastSyncTime = Instant.now();
        log.info("Location capsules reloaded. Total monitored: {}", monitoredCapsules.size());
    }

    /**
     * 启动位置监控任务
     */
    private void startLocationMonitoring() {
        locationMonitorExecutor.scheduleAtFixedRate(
                this::monitorUserLocations,
                0,
                updateInterval,
                TimeUnit.MILLISECONDS
        );
        log.info("Location monitoring started with interval: {} ms", updateInterval);
    }

    /**
     * 位置监控主循环
     */
    private void monitorUserLocations() {
        try {
            if (userLocations.isEmpty()) {
                log.debug("No user locations to monitor");
                return;
            }

            log.debug("Monitoring user locations for {} capsules", monitoredCapsules.size());
            int triggeredCount = 0;

            // 处理所有用户的位置
            for (UserLocation userLocation : userLocations.values()) {
                // 跳过陈旧位置（超过30分钟）
                if (Duration.between(userLocation.getLastUpdate(), Instant.now()).toMinutes() > 30) {
                    continue;
                }

                // 处理该用户的所有胶囊
                triggeredCount += checkTriggersForUser(userLocation);
            }

            if (triggeredCount > 0) {
                log.info("Triggered {} location capsules in this cycle", triggeredCount);
            }
        } catch (Exception e) {
            log.error("Error in location monitoring cycle", e);
        }
    }

    /**
     * 智能触发检查（当用户靠近目标区域时启用详细监控）
     */
    private void checkIntelligentTrigger(Long userId) {
        UserLocation location = userLocations.get(userId);
        if (location == null) return;

        // 查找用户的所有位置胶囊
        List<CapsuleData> userCapsules = monitoredCapsules.values().stream()
                .filter(capsule -> capsule.getUserId().equals(userId))
                .collect(Collectors.toList());

        for (CapsuleData capsule : userCapsules) {
            double distance = GeoUtil.calculateDistance(
                    location.getLatitude(), location.getLongitude(),
                    capsule.getLatitude(), capsule.getLongitude()
            );

            // 如果进入智能区域（默认5公里范围）
            if (distance <= intelligentThreshold) {
                // 为该胶囊启用详细监控
                capsule.setDetailedMonitoring(true);
                log.debug("Enabled detailed monitoring for capsule {} (distance: {}m)",
                        capsule.getId(), (int)distance);

                // 立即检查触发
                checkTriggerForCapsule(capsule, location);
            } else {
                // 离开区域时关闭详细监控
                capsule.setDetailedMonitoring(false);
            }
        }
    }

    /**
     * 检查用户的胶囊触发
     */
    private int checkTriggersForUser(UserLocation userLocation) {
        int triggered = 0;
        Long userId = userLocation.getUserId();

        // 获取用户的所有胶囊
        List<CapsuleData> capsules = monitoredCapsules.values().stream()
                .filter(capsule -> capsule.getUserId().equals(userId))
                .collect(Collectors.toList());

        for (CapsuleData capsule : capsules) {
            // 智能模式下只监控标记的胶囊
            if (updateStrategy == UpdateStrategy.INTELLIGENT && !capsule.isDetailedMonitoring()) {
                continue;
            }

            if (checkTriggerForCapsule(capsule, userLocation)) {
                triggered++;
            }
        }

        return triggered;
    }

    /**
     * 检查单个胶囊是否触发
     */
    private boolean checkTriggerForCapsule(CapsuleData capsule, UserLocation userLocation) {
        double distance = GeoUtil.calculateDistance(
                userLocation.getLatitude(), userLocation.getLongitude(),
                capsule.getLatitude(), capsule.getLongitude()
        );

        // 考虑定位精度
        double effectiveDistance = Math.max(0, distance - userLocation.getAccuracy());

        if (effectiveDistance <= capsule.getTriggerRadius()) {
            log.info("Location capsule triggered: ID={}, Distance={}m (Accuracy: {}m)",
                    capsule.getId(), (int)distance, (int)userLocation.getAccuracy());

            try {
                // 打开胶囊
                capsuleService.openCapsule(capsule.getId());

                // 从监控中移除
                removeFromMonitoring(capsule.getId());
                return true;
            } catch (Exception e) {
                log.error("Failed to open location capsule: " + capsule.getId(), e);
            }
        }

        return false;
    }

    /**
     * 验证是否是有效的位置胶囊
     */
    private boolean isValidLocationCapsule(TimeCapsule capsule) {
        return capsule != null &&
                capsule.getType() == TimeCapsule.CapsuleType.LOCATION &&
                capsule.getLatitude() != null &&
                capsule.getLongitude() != null &&
                capsule.getUser() != null &&
                !capsule.isOpened();
    }

    /**
     * 位置更新策略
     */
    public enum UpdateStrategy {
        INTELLIGENT,    // 智能模式（靠近目标区域时详细监控）
        CONTINUOUS,     // 持续监控（高精度）
        BATTERY_SAVER   // 省电模式（减少更新频率）
    }

    /**
     * 位置胶囊监控数据
     */
    private static class CapsuleData {
        private final Long id;
        private final double latitude;
        private final double longitude;
        private final Long userId;
        private final double triggerRadius;
        private boolean detailedMonitoring = false;

        CapsuleData(Long id, Double latitude, Double longitude, Long userId, double triggerRadius) {
            this.id = id;
            this.latitude = latitude;
            this.longitude = longitude;
            this.userId = userId;
            this.triggerRadius = triggerRadius;
        }

        // Getters
        public Long getId() { return id; }
        public double getLatitude() { return latitude; }
        public double getLongitude() { return longitude; }
        public Long getUserId() { return userId; }
        public double getTriggerRadius() { return triggerRadius; }
        public boolean isDetailedMonitoring() { return detailedMonitoring; }

        // Setters
        public void setDetailedMonitoring(boolean detailedMonitoring) {
            this.detailedMonitoring = detailedMonitoring;
        }
    }

    /**
     * 用户位置数据
     */
    private static class UserLocation {
        private final Long userId;
        private double latitude;
        private double longitude;
        private double accuracy; // 定位精度（米）
        private Instant lastUpdate;

        UserLocation(Long userId, double latitude, double longitude, double accuracy) {
            this.userId = userId;
            this.latitude = latitude;
            this.longitude = longitude;
            this.accuracy = accuracy;
            this.lastUpdate = Instant.now();
        }

        // Getters
        public Long getUserId() { return userId; }
        public double getLatitude() { return latitude; }
        public double getLongitude() { return longitude; }
        public double getAccuracy() { return accuracy; }
        public Instant getLastUpdate() { return lastUpdate; }

        // Setters (添加了缺失的 setLastUpdate)
        public void setLatitude(double latitude) {
            this.latitude = latitude;
        }

        public void setLongitude(double longitude) {
            this.longitude = longitude;
        }

        public void setAccuracy(double accuracy) {
            this.accuracy = accuracy;
        }

        // 添加缺失的 setLastUpdate 方法
        public void setLastUpdate(Instant lastUpdate) {
            this.lastUpdate = lastUpdate;
        }
    }

    // ====================== 状态查询API ======================

    /**
     * 获取监控中的胶囊数量
     */
    public int getMonitoredCapsuleCount() {
        return monitoredCapsules.size();
    }

    /**
     * 获取位置更新的用户数量
     */
    public int getActiveUserLocationCount() {
        return userLocations.size();
    }

    /**
     * 获取上次同步时间
     */
    public Instant getLastSyncTime() {
        return lastSyncTime;
    }
}